package com.weareint.examples.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.weareint.examples.dto.CompanyDTO;
import com.weareint.examples.entity.Company;
import com.weareint.examples.dao.CompanyMapper;
import com.weareint.examples.service.ICompanyService;
import com.weareint.common.beans.ServiceBeans;
import com.weareint.common.constants.Constants;
import com.weareint.common.dto.AbstractDTO;
import com.weareint.common.dto.QueryByIdDto;
import com.weareint.common.dto.QueryByPropsWithOprDto;
import com.weareint.common.dto.UpdateByPropsWithOprDto;
import com.weareint.common.entity.WrapperDecorater;
import com.weareint.common.exceptions.SystemRuntimeException;
import com.weareint.common.utils.PageUtil;
import com.weareint.common.service.AliasesUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.Map;
import java.util.List;
import java.util.stream.Collectors;

/**
 *
 *
 * <pre>
 *      客户与供应商
 * </pre>
 *
 * @author Auto Generator
 * @date 2021-07-16
 */
@Service
@Transactional(rollbackFor = {Exception.class, RuntimeException.class, Error.class})
@Slf4j
public class CompanyServiceImpl extends ServiceImpl<CompanyMapper, Company>
        implements ICompanyService {

    @Autowired private ServiceBeans serviceBeans;

    @Override
    public Company getById(Serializable id, boolean throwExceptionWhenNotFound) {
        if (log.isDebugEnabled()) {
            log.debug(
                    "getById id="
                            + id
                            + ", throwExceptionWhenNotFound="
                            + throwExceptionWhenNotFound);
        }
        if (null == id) {
            return null;
        }
        Company entity = super.getById(id);
        if (null == entity && throwExceptionWhenNotFound) {
            throw new SystemRuntimeException("找不到记录");
        }
        return entity;
    }

    @Override
    public boolean save(Company entity) {
        if (null == entity) {
            throw new SystemRuntimeException("Save entity is null.");
        }
        if (log.isDebugEnabled()) {
            log.debug("save entity = " + JSONObject.toJSONString(entity));
        }
        return super.save(entity);
    }

    @Override
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        if (null == idList || idList.isEmpty()) {
            throw new SystemRuntimeException("Remove by ids, but ids is null.");
        }
        if (log.isDebugEnabled()) {
            log.debug("removeByIds ids = " + JSONObject.toJSONString(idList));
        }
        return super.removeByIds(idList);
    }

    @Override
    public Map<String, Object> findPropsById(QueryByIdDto queryByIdDTO) {
        if (null == queryByIdDTO || null == queryByIdDTO.getId()) {
            return null;
        }
        if (log.isDebugEnabled()) {
            log.debug("findPropsById queryByIdDTO = " + JSONObject.toJSONString(queryByIdDTO));
        }
        QueryWrapper<Company> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(Company.ID, queryByIdDTO.getId());
        WrapperDecorater.decorateSelectForQueryWrapper(
                queryWrapper, queryByIdDTO.getColumns(), Company.COLUMNS, log);
        Company record = getOne(queryWrapper, false);
        if (log.isDebugEnabled()) {
            log.debug(
                    "findPropsById queryByIdDTO = "
                            + JSONObject.toJSONString(queryByIdDTO)
                            + " result = "
                            + JSONObject.toJSONString(record));
        }
        if (null != record) {
            Map<String, Object> data = BeanUtil.beanToMap(record.toDTO());
            AliasesUtils.fullAliases(
                    queryByIdDTO.getAliases(),
                    io.vavr.collection.List.of(data).asJava(),
                    serviceBeans,
                    log);
            return data;
        }
        return null;
    }


    @Override
    public Map<Long, CompanyDTO> findManyPropsByIds(List<Long> ids, List<String> columns) {
        if (null == ids || ids.isEmpty()) {
            return null;
        }
        if (ids.size() > Constants.MAX_COUNT_WHEN_SQL_IN) {
            throw new SystemRuntimeException(
                    "Not Supported Too many count in sql in. max = "
                            + Constants.MAX_COUNT_WHEN_SQL_IN);
        }
        if (log.isDebugEnabled()) {
            log.debug(
                    "findManyPropsByIds ids = "
                            + JSONObject.toJSONString(ids)
                            + ", columns = "
                            + JSONObject.toJSONString(columns));
        }
        QueryWrapper<Company> queryWrapper = new QueryWrapper<>();
        queryWrapper.in(Company.ID, ids);
        if (null != columns && !columns.isEmpty()) {
            if (!columns.contains(Company.ID)) {
                columns = io.vavr.collection.List.ofAll(columns).push(Company.ID).asJava();
            }
            WrapperDecorater.decorateSelectForQueryWrapper(
                    queryWrapper, columns, Company.COLUMNS, log);
        }
        List<Company> list = list(queryWrapper);
        if (null == list || list.isEmpty()) {
            return null;
        }
        return list.stream()
                .map(Company::toDTO)
                .collect(Collectors.toMap(AbstractDTO::getId, it -> it));
    }

    @Override
    public Page<Map<String, Object>> findPropsByPage(
            QueryByPropsWithOprDto queryByPropsWithOprDto) {
        if (null == queryByPropsWithOprDto) {
            return null;
        }
        if (log.isDebugEnabled()) {
            log.debug(
                    "findPropsByPage queryByPropsWithOprDto = "
                            + JSONObject.toJSONString(queryByPropsWithOprDto));
        }
        Page<Company> pageable =
                PageUtil.createPageable(
                        queryByPropsWithOprDto.getPage(), queryByPropsWithOprDto.getSize());
        QueryWrapper<Company> queryWrapper = new QueryWrapper<>();
        WrapperDecorater.decorateSelectForQueryWrapper(
                queryWrapper, queryByPropsWithOprDto.getColumns(), Company.COLUMNS, log);
        WrapperDecorater.decorateWhereForWrapper(
                queryWrapper, queryByPropsWithOprDto.getWherePropsWithOprs(), Company.COLUMNS, log);
        WrapperDecorater.decorateOrderByForQueryWrapper(
                queryWrapper, queryByPropsWithOprDto.getOrderByProps(), Company.COLUMNS, log);
        Page<Map<String, Object>> mapPage =
                PageUtil.convertPage(
                        page(pageable, queryWrapper),
                        it -> BeanUtil.beanToMap(it.toDTO()));
        if (log.isDebugEnabled()) {
            log.debug(
                    "findPropsByPage queryByPropsWithOprDto = "
                            + JSONObject.toJSONString(queryByPropsWithOprDto)
                            + " result = "
                            + JSONObject.toJSONString(mapPage));
        }
        AliasesUtils.fullAliases(
                queryByPropsWithOprDto.getAliases(), mapPage.getRecords(), serviceBeans, log);
        return mapPage;
    }

    @Override
    public void update(UpdateByPropsWithOprDto updateByPropsWithOprDto) {
        if (null == updateByPropsWithOprDto) {
            return;
        }
        if (log.isDebugEnabled()) {
            log.debug(
                    "update updateByPropsWithOprDto = "
                            + JSONObject.toJSONString(updateByPropsWithOprDto));
        }
        UpdateWrapper<Company> updateWrapper = new UpdateWrapper<>();
        WrapperDecorater.decorateWhereForWrapper(
                updateWrapper,
                updateByPropsWithOprDto.getWherePropsWithOprs(),
                Company.COLUMNS,
                log);
        WrapperDecorater.decorateSetForUpdateWrapper(
                updateWrapper, updateByPropsWithOprDto.getUpdateProps(), Company.COLUMNS, log);
        update(updateWrapper);
    }
}
